package net.sf.odinms.exttools.doclet.pages;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.tools.doclets.internal.toolkit.util.DirectoryManager;
import com.sun.tools.doclets.internal.toolkit.util.Util;
import net.sf.odinms.exttools.doclet.AbstractPageWriter;
import net.sf.odinms.exttools.doclet.Doclet;

/**
 * Creates "{packagepath}/package-use.html" detailing package use.
 */
@SuppressWarnings("unchecked")
public final class PackageUse extends AbstractPageWriter {
	/** The current package being documented. */
	private PackageDoc pkg;
	
	/** The previous package in the alpha-order list. */
	private PackageDoc prev;
	
	/** The next package in the alpha-order list. */
	private PackageDoc next;
	
	/**
	 * Map of a package to the classes it uses.
	 */
	private SortedMap<String, Set<ClassDoc>> usingPackageToUsedClasses = null;
	
	/**
	 * Generate a page documenting usage of a given package.
	 * 
	 * @param pkg The package for which to document usage.
	 * @param prev The previous package in the alpha-ordered list, if exists.
	 * @param next The following package in the alpha-ordered list, if exists.
	 */
	public static void generatePackageUse(PackageDoc pkg, PackageDoc prev,
			PackageDoc next) {
		String filename = "package-use" + CONF.ext;
		String pathToFile = DirectoryManager.getDirectoryPath(pkg);
		try {
			new PackageUse(filename, pathToFile, pkg, prev, next);
		}
		catch (IOException exc) {
			throw Doclet.exception(exc, pathToFile + SLASH + filename);
		}
	}
	
	/**
	 * Initialize and create usage page for the specified package.
	 * 
	 * @param filename The desired name of the file (with extension).
	 * @param pathToFile The path from the document root to this file.
	 * @param pkg Package for which a usage file is to be generated.
	 * @param prev The previous package in the alpha-ordered list.
	 * @param next The following package in the alpha-ordered list.
	 * @throws IOException If {@link java.io.FileOutputStream} creation fails.
	 */
	private PackageUse(String filename, String pathToFile, PackageDoc pkg,
			PackageDoc prev, PackageDoc next) throws IOException {
		super(filename, pathToFile);
		pageType = PageType.PACKAGE_USE;
		CONF.currentPkg = pkg;
		this.pkg = pkg;
		this.prev = prev;
		this.next = next;
		
		windowTitle = pkg.name();
		printXhtmlHeader();
		printEntityCaption(pkg, "Usage of Package");
		
		createPackageToClassMapping();
		
		if (usingPackageToUsedClasses.isEmpty()) {
			println(CONF.propertyText("use.No_usage_of_0", pkg.name()));
		} else {
			// Print table of packages that use this package.
			println(openDivWithID("Summaries"));
			if (CONF.packages.length > 1) {
				println(open("h2")
						+ CONF.propertyText("use.Packages_that_use_0",
								linkToLabelHref(pkg.name(), "package-summary"
										+ CONF.ext)) + close("h2"));
				println(open("table"));
				for (String pkgName : usingPackageToUsedClasses.keySet()) {
					PackageDoc cur = CONF.root.packageNamed(pkgName);
					println(open("tr"));
					printTH(linkToLabelHref(cur.name(), "#" + cur.name()));
					printTD(getCommentSummary(cur));
					println(close("tr"));
				}
				println(close("table"));
			}
			println(close("div") + getComment("Summaries"));
			
			println(openDivWithID("Details"));
			// generateClassList();
			
			for (String packageName : usingPackageToUsedClasses.keySet()) {
				PackageDoc usingPackage = CONF.root.packageNamed(packageName);
				
				String label =
						CONF.propertyText("use.Classes_used_by_0",
								getPackageLink(usingPackage,
										Util.getPackageName(usingPackage),
										false));
				println(new TagBuilder("h3").add("id", usingPackage.name()).getOpenTextClose(
						label));
				
				println(open("table"));
				for (ClassDoc cur : usingPackageToUsedClasses.get(packageName)) {
					println(open("tr"));
					printTH(linkToLabelHref(cur.name(), "class-use" + SLASH
							+ cur.name() + CONF.ext + "#" + packageName));
					printTD(getCommentSummary(cur));
					println(close("tr"));
				}
				println(close("table"));
			}
			println(close("div") + getComment("Details"));
		}
		printXhtmlFooter();
		this.close();
	}
	
	/**
	 * Create a map between all classes in the current package and any packages
	 * that uses them.
	 */
	private void createPackageToClassMapping() {
		usingPackageToUsedClasses = new TreeMap<String, Set<ClassDoc>>();
		for (ClassDoc usedClass : pkg.allClasses()) {
			Set usingClasses =
					(Set) CONF.classUseMapper.classToClass.get(usedClass.qualifiedName());
			if (usingClasses != null) {
				ClassDoc usingClass;
				for (Iterator it = usingClasses.iterator(); it.hasNext();) {
					usingClass = (ClassDoc) it.next();
					PackageDoc usingPackage = usingClass.containingPackage();
					Set<ClassDoc> usedClasses =
							(Set<ClassDoc>) usingPackageToUsedClasses.get(usingPackage.name());
					if (usedClasses == null) {
						usedClasses = new TreeSet<ClassDoc>();
						usingPackageToUsedClasses.put(usingPackage.name(),
								usedClasses);
					}
					usedClasses.add(usedClass);
				}
			}
		}
	}
	
	/** Link "Package" to the current package's summary. */
	protected void navLinkPackage() {
		println(listItem(linkToLabelHrefTitle(PACKAGE, "package-summary"
				+ CONF.ext, CONF.propertyText("navtitle.Package", pkg.name()))));
	}
	
	/** Highlight "Use" as current section, don't create link. */
	protected void navLinkUse() {
		println(listItemCurrent(USE));
	}
	
	/** Link "Tree" to the current package's tree. */
	protected void navLinkTree() {
		println(listItem(linkToLabelHrefTitle(TREE, "package-tree" + CONF.ext,
				CONF.propertyText("navtitle.Tree.package", pkg.name()))));
	}
	
	/** Print links to previous and next packages, or static label if none. */
	protected void navPreviousNext() {
		println(openULWithID("PreviousNext"));
		println(listItem(linkToLabelHref(PREV_PKG, hrefToDoc(prev)
				+ "package-use" + CONF.ext))
				+ listItemLast(linkToLabelHref(NEXT_PKG, hrefToDoc(next)
						+ "package-use" + CONF.ext)));
		println(close("ul"));
	}
	
}
